﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SPMS.Log.Utility;
using SPMS.Log.Repository;

namespace SPMS.Log.Core
{
    /// <summary>
    /// 抽象日志记录器
    /// </summary>
    /// <remarks>提供了日志记录器实现的默认抽象基类</remarks>
    /// <history>
    /// [zanezeng]               2009/9/24 17:31    创建
    /// </history>
    public abstract class AbstractLogger : ILogger, ILogAppenderAttachable, IDisposable
    {
        #region ---Constructor

        /// <summary>
        /// 初始化类型<see cref="AbstractLogger"/>的新实例
        /// </summary>
        /// <param name="name">日志记录器的名称</param>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/30 13:24    创建
        /// </history>
        protected AbstractLogger( string name )
            : this( name, Level.All, null )
        {
        }

        /// <summary>
        /// 初始化类型<see cref="AbstractLogger"/>的新实例
        /// </summary>
        /// <param name="name">日志记录器的名称</param>
        /// <param name="threshold">日志记录器允许输出的日志级别</param>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/30 13:27    创建
        /// </history>
        protected AbstractLogger( string name, Level threshold )
            : this( name, threshold, null )
        {
        }

        /// <summary>
        /// 初始化类型<see cref="AbstractLogger"/>的新实例
        /// </summary>
        /// <param name="name">日志记录器的名称</param>
        /// <param name="threshold">日志记录器允许输出的日志级别</param>
        /// <param name="repository">日志记录器所属的日志存储器</param>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/10/13 15:23    创建
        /// </history>
        protected AbstractLogger( string name, Level threshold, ILoggingRepository repository )
        {
            //保存参数
            this.m_Name = (null == name) ? string.Empty : name;
            this.m_Threshold = (null == threshold) ? Level.All : threshold;
            this.m_Repository = repository;
        }

        /// <summary>
        /// 析构函数，用于释放<see cref="AbstractLogger"/>实例的非托管资源
        /// </summary>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2010/1/5 17:26    创建
        /// </history>
        ~AbstractLogger()
        {
            //释放非托管资源
            this.Dispose( false );
        }

        #endregion

        #region ---ILogger

        /// <summary>
        /// 获得日志记录器的名称
        /// </summary>
        /// <value></value>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/24 11:54    创建
        /// </history>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/30 13:23    创建
        /// </history>
        public string Name
        {
            get
            {
                return this.m_Name;
            }
        }

        /// <summary>
        /// 获得日志记录器所属的存储器
        /// </summary>
        /// <value>日志记录器所属的存储器</value>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/10/13 15:19    创建
        /// </history>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/10/13 15:20    创建
        /// </history>
        public ILoggingRepository Repository
        {
            get
            {
                return this.m_Repository;
            }
            set
            {
                this.m_Repository = value;
            }
        }

        /// <summary>
        /// 获得或者设置日志记录器允许输出的日志级别
        /// </summary>
        /// <value>日志记录器允许输出的日志级别</value>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/30 13:28    创建
        /// </history>
        public Level Threshold
        {
            get
            {
                return this.m_Threshold;
            }
            set
            {
                //保存值
                this.m_Threshold = (null == value) ? Level.All : value;
            }
        }

        /// <summary>
        /// 判断当前日志记录器是否能够记录给定级别的日志信息
        /// </summary>
        /// <param name="level">用于判定的日志级别</param>
        /// <returns>
        /// 	<c>true</c>：允许记录<br/>
        /// 	<c>false</c>：不允许记录
        /// </returns>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/24 17:12    创建
        /// </history>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/30 13:33    创建
        /// </history>
        public bool IsLevelEnabled( Level level )
        {
            //判断日志级别是否为空引用
            if (null == level)
            {
                //如果日志级别为空引用，则总是不允许
                return false;
            }

            //判断当前日志追加器是否允许输出
            if (level < this.Threshold)
            {
                //如果当前日志追加器不允许输出，则直接返回不允许
                return false;
            }

            //判断日志存储器是否允许输出
            if (null != this.Repository && level < this.Repository.DefaultLevel)
            {
                //如果日志存储器不允许输出，则直接返回不允许输出
                return false;
            }

            //默认返回允许
            return true;
        }

        /// <summary>
        /// 将给定的日志条件记录到当前日志记录器中
        /// </summary>
        /// <param name="entry">要记录的日志条目</param>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/24 17:15    创建
        /// </history>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/30 13:35    创建
        /// </history>
        public void WriteLog( LogEntry entry )
        {
            //判断需要记录的日志条目是否为NULL
            if (null == entry)
            {
                //输出日志
                if (LoggingContext.MetaLog.IsWarnEnabled)
                {
                    LoggingContext.MetaLog.Warn( "需要记录的日志条目为NULL" );
                }

                //如果需要记录的日志条目为NULL，则直接返回
                return;
            }

            //判断日志条目是否允许输出
            if (this.IsLevelEnabled( entry.Level ))
            {
                try
                {
                    //包含扩展属性
                    this.IncludeExtendProperties( entry );

                    //写入日志
                    this.AppendEntry( entry );
                }
                catch (Exception exception)
                {
                    //输出日志
                    if (LoggingContext.MetaLog.IsErrorEnabled)
                    {
                        LoggingContext.MetaLog.Error( exception, "日志记录器'{0}'写入日志失败", this.Name );
                    }
                }
            }
        }

        /// <summary>
        /// 将给定的日志信息记录到当前日志记录器中
        /// </summary>
        /// <param name="stackBoundaryType">调用堆栈分界类型</param>
        /// <param name="level">日志消息的级别</param>
        /// <param name="message">日志消息包含的消息对象</param>
        /// <param name="exception">日志消息包含的异常信息</param>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/10/13 15:08    创建
        /// </history>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/10/13 15:09    创建
        /// </history>
        public void WriteLog( Type stackBoundaryType, Level level, object message, Exception exception )
        {
            //判断日志条目是否允许输出
            if (this.IsLevelEnabled( level ))
            {
                try
                {
                    //创建日志条目
                    LogEntry entry = new LogEntry( stackBoundaryType, this.Name, level, message, exception );

                    //包含扩展属性
                    this.IncludeExtendProperties( entry );

                    //写入日志
                    this.AppendEntry( entry );
                }
                catch (Exception ex)
                {
                    //输出日志
                    if (LoggingContext.MetaLog.IsErrorEnabled)
                    {
                        LoggingContext.MetaLog.Error( ex, "日志记录器'{0}'写入日志信息'{1}'失败", this.Name, message );
                    }
                }
            }
        }

        /// <summary>
        /// 关闭当前日志记录器
        /// </summary>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/10/19 9:50    创建
        /// </history>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/10/19 9:52    创建
        /// </history>
        public void Close()
        {
            //处置日志记录器
            this.Dispose();
        }

        #endregion

        #region ---ILogAppenderAttachable

        /// <summary>
        /// 获得关联的所有日志输出器
        /// </summary>
        /// <value>关联的所有日志输出器</value>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/25 12:11    创建
        /// </history>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/30 13:41    创建
        /// </history>
        public ILogAppender[] Appenders
        {
            get
            {
                return this.m_LogAppenderAttachable.Appenders;
            }
        }

        /// <summary>
        /// 获得给定名称的日志输出器
        /// </summary>
        /// <param name="name">要获得的日志输出器的名称</param>
        /// <returns>给定名称的日志输出器</returns>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/25 12:18    创建
        /// </history>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/30 13:42    创建
        /// </history>
        public ILogAppender GetAppender( string name )
        {
            return this.m_LogAppenderAttachable.GetAppender( name );
        }

        /// <summary>
        /// 添加日志输出器
        /// </summary>
        /// <param name="appender">要添加的日志输出器</param>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/25 12:12    创建
        /// </history>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/30 13:42    创建
        /// </history>
        public void AddAppender( ILogAppender appender )
        {
            this.m_LogAppenderAttachable.AddAppender( appender );
        }

        /// <summary>
        /// 删除指定日志输出器
        /// </summary>
        /// <param name="appender">要删除的日志输出器</param>
        /// <returns>
        /// 	<c>true</c>：删除成功<br/>
        /// 	<c>false</c>：删除失败
        /// </returns>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/25 12:14    创建
        /// </history>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/30 13:48    创建
        /// </history>
        public bool RemoveAppender( ILogAppender appender )
        {
            return this.m_LogAppenderAttachable.RemoveAppender( appender );
        }

        /// <summary>
        /// 删除给定名称的日志输出器
        /// </summary>
        /// <param name="name">要删除的日志输出器的名称</param>
        /// <returns></returns>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/25 12:17    创建
        /// </history>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/30 13:42    创建
        /// </history>
        public ILogAppender RemoveAppender( string name )
        {
            return this.m_LogAppenderAttachable.RemoveAppender( name );
        }

        /// <summary>
        /// 清除所有的日志输出器
        /// </summary>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/25 12:17    创建
        /// </history>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/30 13:42    创建
        /// </history>
        public void ClearAppenders()
        {
            this.m_LogAppenderAttachable.ClearAppenders();
        }

        #endregion

        #region ---IDisposable

        /// <summary>
        /// 执行与释放或重置非托管资源相关的应用程序定义的任务
        /// </summary>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/10/19 9:54    创建
        /// </history>
        public void Dispose()
        {
            //释放托管资源
            this.Dispose( true );

            //阻止回收
            GC.SuppressFinalize( this );
        }

        #endregion

        #region ---Property

        /// <summary>
        /// 获得一个值，该值用于判断日志记录器是否已经关闭
        /// </summary>
        /// <value>
        /// 	<c>true</c>：日志记录器已经关闭<br/>
        /// 	<c>false</c>：日志记录器尚未关闭
        /// </value>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/10/19 9:58    创建
        /// </history>
        public bool IsClosed
        {
            get
            {
                return this.m_IsClosed;
            }
        }

        #endregion

        #region ---Protected Method

        /// <summary>
        /// 添加一条日志记录
        /// </summary>
        /// <param name="entry">要添加的日志记录条目</param>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/10/9 9:23    创建
        /// </history>
        protected abstract void AppendEntry( LogEntry entry );

        /// <summary>
        /// 通知日志记录器关闭
        /// </summary>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/10/19 9:53    创建
        /// </history>
        protected virtual void OnClose()
        {
        }

        /// <summary>
        /// 执行与释放或重置非托管资源相关的应用程序定义的任务
        /// </summary>
        /// <param name="isDisposing">是否释放托管资源</param>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/10/19 9:55    创建
        /// </history>
        protected virtual void Dispose( bool isDisposing )
        {
            //判断是否已经关闭
            if (this.m_IsClosed)
            {
                //如果已经关闭，则直接返回
                return;
            }

            //设置已经关闭
            this.m_IsClosed = true;

            //关闭日志记录器
            this.OnClose();
        }

        #endregion

        #region ---Private Method

        /// <summary>
        /// 向给定的日志条目中添加扩展属性
        /// </summary>
        /// <param name="entry">要包含扩展属性的日志条目</param>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/10/21 11:36    创建
        /// </history>
        private void IncludeExtendProperties( LogEntry entry )
        {

        }

        #endregion

        #region ---Field

        /// <summary>
        /// 日志记录器的名称
        /// </summary>
        private string m_Name;

        /// <summary>
        /// 日志记录器允许输出的日志级别
        /// </summary>
        private Level m_Threshold;

        /// <summary>
        /// 日志记录器所处的存储器
        /// </summary>
        private ILoggingRepository m_Repository;

        /// <summary>
        /// 用于记录是否已经关闭
        /// </summary>
        private bool m_IsClosed;

        /// <summary>
        /// 日志记录器附加器
        /// </summary>
        private LogAppenderAttachableImplement m_LogAppenderAttachable = new LogAppenderAttachableImplement();

        /// <summary>
        /// 堆栈分界类型
        /// </summary>
        private readonly static Type TYPE_STACKBOUNDARY = typeof( AbstractLogger );

        #endregion
    }
}
